/*
	Copyright (C) 2011 Salil Bhagurkar

	This file is part of illusion

	illusion is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as
	published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	illusion is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with illusion. 
	If not, see <http://www.gnu.org/licenses/>.
*/

#include <arch/arch.h>
#include <klib/lib.h>
#include <kernel/console.h>
#include <kernel/timing.h>

#define MS_DEFAULT 1000
#define US_DEFAULT 10

static volatile bool timer_flag = true, timer_flag_ref = true;
//Set default values in case the calibration results in a zero, or
//if the delay functions are called before the calibration
static uint_t ms_loops = MS_DEFAULT, us_loops = US_DEFAULT;
static long ms_loops_diff;
static void delay_calib_timer()
{
	timer_flag = false;
}

void ms_delay(uint_t count)
{
	volatile uint_t loops;
	while(count--) {
		loops = 0;
		while(loops < ms_loops) {
			loops++;
		}
	}
}

void us_delay(uint_t count)
{
	volatile uint_t loops;
	while(count--) {
		loops = 0;
		while(loops < us_loops) {
			loops++;
		}
	}
}

static void calib()
{
	volatile uint_t loops = 0;
	//Sync with the timer
	timer_flag = true;
	while(timer_flag);
	//Reset and begin counting
	timer_flag = true;
	while(timer_flag == timer_flag_ref) {
		loops++;
	}
	ms_loops = loops;
	if(!ms_loops)
		ms_loops = MS_DEFAULT;
	us_loops = loops / 1000;
	if(!us_loops)
		us_loops = US_DEFAULT;
	initmsg("Delay loops: ms = %u, us = %u\n", ms_loops, us_loops);
}


int timing_init()
{
	set_timer_handler(delay_calib_timer, 1000);
	calib();
	return 0;
}
